﻿using H.Utils.DataStruct;
using System.Collections.Concurrent;
using System.Text;
using System.Threading;

namespace H.Logger.Logs
{
    internal class HLogQueue
    {
        /// <summary>
        /// 内部保存的线程安全队列
        /// </summary>
        private readonly ConcurrentQueue<HLogInfo> _Queue = new ConcurrentQueue<HLogInfo>();

        /// <summary>
        /// 内部信号量,用于通知消费者进行消费
        /// </summary>
        private readonly AutoResetEvent _AutoResetEvent = new AutoResetEvent(false);

        /// <summary>
        /// StringBuilder缓冲池
        /// </summary>
        private readonly CommonPool<StringBuilder> _StringBuilderPool = new CommonPool<StringBuilder>();

        /// <summary>
        /// 当前是否是挂起状态,如果是挂起状态,则会保留一定长度的缓存,超出长度部分的日志将不会保存
        /// </summary>
        public bool IsHangUp { get; set; } = true;

        /// <summary>
        /// 最大缓冲长度(超出的长度在Queue被挂起时,将被会略)
        /// </summary>
        private readonly int _MaxLength;

        /// <summary>
        /// 初始化一个Log日志队列
        /// </summary>
        public HLogQueue(int maxLength = 1000)
        {
            _MaxLength = maxLength;
        }

        /// <summary>
        /// 入队一个日志信息
        /// </summary>
        /// <param name="logInfo"></param>
        public void Enqueue(HLogInfo logInfo)
        {
            if (IsHangUp)
            {
                if (_Queue.Count >= _MaxLength)
                {
                    _Queue.TryDequeue(out _);
                }
            }
            _Queue.Enqueue(logInfo);
            _AutoResetEvent.Set();
        }

        /// <summary>
        /// 出队日志信息
        /// </summary>
        /// <returns>返回一条或多条日志的文本表示,至多一次返回10条</returns>
        public string Dequeue()
        {
            StringBuilder sb = _StringBuilderPool.Malloc();
            sb.Clear();
            _AutoResetEvent.WaitOne();
            try
            {
                int i = 10;  //计数,最多只能10条合并输出
                while (i-- > 0 && _Queue.TryDequeue(out HLogInfo logInfo))
                {
                    sb.Append(logInfo.ToString());
                }
                return sb.ToString();
            }
            finally
            {
                _StringBuilderPool.Free(sb);
            }
        }
    }
}
